package mysql

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"gitee.com/zibianqu/fyzdb/lib"
	"gitee.com/zibianqu/fyzdb/lib/rand"
	"gitee.com/zibianqu/fyzdb/lib/str"
	"gitee.com/zibianqu/fyzdb/lib/variable"
	"github.com/spf13/cast"
)

// 获取字段的名称并且附上随机字符串，让他变唯一
func getRealField(field string) string {
	randStr := rand.String(6)
	// unid := lib.UniqueId()
	unid := rand.GetRandomWithAll(1000000, 9999999)
	if str.Obj().Contains(field, ".") {
		spArr := strings.Split(field, ".")
		f := spArr[1]
		return fmt.Sprintf("%s_%s_%d", f, randStr, unid)
	}
	return fmt.Sprintf("%s_%s_%d", field, randStr, unid)
}

// 正则获取字符串的字段
func regexBindField(sql string, bpToMap map[string]any) []string {
	re := regexp.MustCompile(":([\\w|\\d|_]*)")
	fieldArr := re.FindAllStringSubmatch(sql, -1)
	bindField := make([]string, 0)
	for _, v := range fieldArr {
		field := v[1]
		if variable.InKeyMap[string](field, bpToMap) {
			bindField = append(bindField, field)
		}
	}
	return bindField
}

// sql参数绑定
func sqlBindParam(sql string, bpToMap map[string]any, isLog bool) (string, []any, string) {
	bindField := regexBindField(sql, bpToMap)
	bpArr := make([]any, 0)
	logSql := sql
	for _, f := range bindField {
		logSql = strings.ReplaceAll(logSql, ":"+f, "'"+cast.ToString(bpToMap[f])+"'")
		if isLog {
			sql = strings.ReplaceAll(sql, ":"+f, "'"+cast.ToString(bpToMap[f])+"'")
		} else {
			sql = strings.ReplaceAll(sql, ":"+f, "?")
		}
		bpArr = append(bpArr, bpToMap[f])
	}
	return sql, bpArr, logSql
}

// 数据库字段映射
func FieldReflect(field, tp string, v any) (value any, err error) {
	value = v
	// 先强转字符串，在转为对应类型
	//tmp := lib.Str.Conversion(v)
	_, isUint8 := v.([]uint8)
	if isUint8 {
		v = string(v.([]uint8))
	}
	// log.Println(field, tp, fmt.Sprintf("%T", v), v, isUint8)
	if variable.IsEmpty(v) {
		value = v
		return
	}
	switch tp {
	case "TINYINT", "SMALLINT", "INT", "INTEGER", "YEAR", "MEDIUMINT":
		value = cast.ToInt64(v)
		break
	case "BIGINT":
		value = cast.ToInt64(v)
		break
	case "DECIMAL":
		value = cast.ToFloat64(v)
		break
	case "FLOAT":
		value = cast.ToFloat64(v)
		break
	case "DOUBLE":
		value, _ = v.(float64)
		break
	case "VARCHAR", "CHAR", "TEXT", "JSON":
		value = cast.ToString(v)
		break
	case "DATETIME":
		if _, ok := v.(string); ok {
			value, err = time.ParseInLocation(lib.TimeFormat, v.(string), time.Local)
			break
		}
		value = v.(time.Time)
		break
	case "DATE":
		if _, ok := v.(string); ok {
			value, err = time.ParseInLocation(lib.DateFormat, v.(string), time.Local)
			break
		}
		value = v.(time.Time)
		break
	case "TIME", "TIMESTAMP":

		if _, ok := v.(string); ok {
			value, err = time.ParseInLocation(lib.TimeFormat, v.(string), time.Local)
			break
		}
		value = v.(time.Time)
		break
	case "UNSIGNED INT":
		value = cast.ToInt64(v)
		break
	default:
		fmt.Println(field + "【" + tp + "】 unknown or unSupport type in mysql")
		break
	}
	return
}
